package cn.b504.qpcr.entity

import com.fasterxml.jackson.databind.ObjectMapper

class Data : OperationInfo(), Cloneable {
  var experimentName = "" // 实验名
  var barcode = ""
  var userName = ""       // 用户名，即工作空间名
  var instrumentName = "" // 仪器名
  var reagentsType = "" // 控制 protocol 初始化步骤
  var runModeIsSample = false  // 设置加热块模式
  var experimentIdentity = ""
  var controlTray = 0.0f //控制开关舱门
  var reactionVolume: Short = 25
  var hotLidMode = true                     // 设置热盖是否启用
  var coverTemp = 105.0f     // 设置热盖温度
  var lidCloseTemp = 30.0f // 设置热盖关闭温度
  var comments = ""
  var analysisMethodSetting = AnalysisMethodSetting()
  var wells: List<Well> = ArrayList()
  var targets: List<PlateSetting.Target> = ArrayList()  // 设置到孔板上的全部 Target
  var plateSetting = PlateSetting()
  var channelNameList = ChannelNameList()
  var coefficients: List<Coefficient> = ArrayList()
  var protocol = Protocol()
  var sampleTemperature: List<Temperature> = ArrayList()  // 记录实时温度
  var lidTemperature: List<Temperature> = ArrayList()     // 记录实时热盖温度
  var time = Time()
  var pcrDataOrigin = PcrDataOriginList()
  var meltDataOrigin: List<List<Float>> = ArrayList()
  var quanlityControl = QuanlityControl()
  var version = "1.0"

  public override fun clone(): Data {
    val objectMapper = ObjectMapper();
    return objectMapper.readValue(objectMapper.writeValueAsString(this), this.javaClass)
  }
}

class AnalysisMethodSetting {
  object Mode {
    const val THRESHOLD = "Threshold"
    const val CUSTOM_THRESHOLD = "CustomThreshold"
    const val REGRESSION = "Regression"
    const val EXTREMUM = "Extremum"
    const val CQMAN = "CqMan"
  }

  object Method {
    const val RAW_DATA = "RawData"
    const val BASELINE_CORRECTION = "BaselineCorrection"
    const val BASELINE_SUBTRACTED_CURVE_FIT = "BaselineSubtractedCurveFit"
  }

  var method = Method.BASELINE_SUBTRACTED_CURVE_FIT
  var mode = Mode.THRESHOLD
  var startCycle = 3
  var endCycle = 15
  var baseLineAuto = true
}

class Coefficient {
  var name = ""
  var channel: Short = -1
  var coefficient = emptyArray<Double>()

  fun copy(): Coefficient {
    val coe = Coefficient()
    coe.name = this.name;
    coe.channel = this.channel;
    coe.coefficient = this.coefficient.clone()
    return coe
  }
}

class Well {
  companion object Type {
    const val UNDEFINED = ""
    const val STD = "Std"
    const val UNK = "Unk"
    const val NTC = "Ntc"
    const val NEG = "Neg"
    const val POS = "Pos"
    const val NRT = "Nrt"
  }

  var col: Short = -1
  var row: Short = -1
  var show = true
  var selected = false
  var type = UNDEFINED
  var sampleName = ""
  var sampleColor = ""
  var sampleUuid = ""
  var sampleControl = false
  var lines = arrayOf(Line(), Line(), Line(), Line(), Line(), Line())

  class Line {
    var omit = false
    var sigLevel = 5F
    var baseStartCycle = 3
    var baseEndCycle = 15
    var cq = -1F
    var cqMean = -1F
    var cqSd = -1F
    var sq = -1F
    var sqMean = -1F
    var sqSd = -1F
    var quantificationOrigin: List<Float> = ArrayList()
    var quantificationBaseline: List<Float> = ArrayList()
    var quantificationCurveFitter: List<Float> = ArrayList()
    var quantificationOpt: List<Float> = ArrayList()

    fun copyQuantificationOrigin() = this.quantificationOrigin.toFloatArray().clone().toMutableList()
  }

  var targets: List<PlateSetting.Target> = ArrayList()  // 当前孔中设置的 Target
  var meltData: List<Float> = ArrayList()
  var meltPeak: List<Float> = ArrayList()
  var meltTemperature = -1F
  var groupName = ""
  var groupColor = "#000000"
  var groupUuid = ""
  var heatMapColor = ""
}

class PlateSetting {
  var targets: List<Target> = ArrayList() // 全部的 Target 设置，包括未设置到 Plate 上的
  var samples: List<Sample> = ArrayList()
  var standard: StandardSetting = StandardSetting()

  class Target {
    var uuid = ""
    var opt = false
    var show = true
    var name = ""
    var color = "#000000"
    var channel = ""
    var channelIndex: Short = 0  // 0-based
    var quencher = ""
    var reference = false
    var k = -1.0
    var b = -1.0
    var e = -1.0
    var r2 = -1.0
    var threshold = 0.01F
    var meltThreshold = -1F
    var comments = ""
    var cutOff = CutOff()

    class CutOff {
      var left = 30
      var right = 70
    }
  }

  class Sample {
    var uuid = ""
    var opt = false
    var type = ""
    var comments = ""
    var color = "#000000"
    var name = ""
    var control = false
    var id = ""
    var mark = ""
  }

  class StandardSetting {
    var selectTarget: List<String> = ArrayList()
    var startingAmount = 1
    var standardNumber = 5
    var factor = 1
    var dilutionFactor = 10
    var unit = "copies/μL"
    var replicates = 2
    var increasing = true
    var assignment = 1
    var showInitialQuantity = ""
    var replicateArrange = ""
    var name = ""
    var initialQuantity = ""
  }
}

class ChannelNameList {
  var channel1: List<String> = ArrayList()
  var channel2: List<String> = ArrayList()
  var channel3: List<String> = ArrayList()
  var channel4: List<String> = ArrayList()
  var channel5: List<String> = ArrayList()
  var channel6: List<String> = ArrayList()
}

class PcrDataOriginList {
  var channel1: List<List<Float>> = ArrayList()
  var channel2: List<List<Float>> = ArrayList()
  var channel3: List<List<Float>> = ArrayList()
  var channel4: List<List<Float>> = ArrayList()
  var channel5: List<List<Float>> = ArrayList()
  var channel6: List<List<Float>> = ArrayList()
}

class QuanlityControl {
  var negCq = 38
  var ntcCq = 38
  var posCq = 35
  var efficiency = Efficiency()
  var stdCurveR2 = 0.98F
  var cqStdDev = 0.5F

  class Efficiency {
    var min = 90
    var max = 110
  }
}

class Protocol {
  var name = ""
  var stages: List<Stage> = ArrayList() // 设置的流程
  var positions = byteArrayOf(1, 1, 1, 1, 1, 1) // 采集的位置
  var channels = byteArrayOf(1, 1, 1, 1, 1, 1)  // 采集的通道
  var current = Current() // 当前状态

  class Stage {
    companion object State {
      const val PRE_READ = "Pre-read"
      const val HOLD = "Hold"
      const val AMPLIFICATION = "Amplification"
      const val POST_READ = "Post-read"
      const val MELT = "Melt"
      const val INFINITE_HOLD = "Infinite Hold"
    }

    var state = HOLD
    var steps: List<Step> = ArrayList()
    var cycle: Short = 40
    var hrMeltingCurveMode = false

    class Step {
      var temperature = 95F
      var gradient = 0.5F
      var time = 60
      var record = false
      var autoDelta = AutoDelta()
      var gradientDeltaTemperature = Gradient()

      class AutoDelta {
        var checkAutoPauseBefore = false
        var checkAutoPauseAfter = false
        var checkAutoDeltaTemperature = false
        var autoDeltaTemperature = 0.5f
        var checkAutoDeltaTime = false
        var autoDeltaTime: Short = 0
        var checkRampRate = false
        var rampRate = 0f
      }

      class Gradient {
        var checked = false
        var start = 95.0f
        var end = 95.0f
      }
    }
  }

  class Current {
    var state = ""
    var cycle = 0
    var pageAllCycle = 0
    var startTemperature = 0
    var endTemperature = 0
    var stepHoldTime = 0
    var pageNum = -1
    var percent = -1
    var stepNum = -1
    var stepTime = -1
    var temperature = -1
  }
}

class Temperature {
  var time = 0L
  var temperature = 0.0
}

class Time {
  var startTimestamp = 0L
  var currentTimestamp = 0L
  var remainTime = 0
}
